package com.fare.taluo.conf;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.fare.taluo.util.ClassUtils;

public class ConfigContainer implements  Serializable{
	protected static Logger logger = Logger.getLogger(ConfigContainer.class);
	
	private final static String ALL_FILE = "ALL_FILE";
	/**
	 * 
	 */
	private static final long serialVersionUID = -6872344806680589604L;
	/**
	 * 配置文件的字段/值缓存对象
	 * Map<String, Map<String, String>> 第一个String为文件名,后面的Map为读取的属性文件键值对
	 */
	private Map<String, Map<String, String>> propertyCache = new HashMap<String,Map<String, String>>();
	/**
	 * 加载器缓存
	 * Map<String, ConfigLocalLoader> 第一个String为存储文件名
	 */
	private Map<String, ConfigLocalLoader> loaderCache = new HashMap<String,ConfigLocalLoader>();
	
	private static ConfigContainer _ConfigContainer = null;
	
	public static ConfigContainer getInstance(){
		if(_ConfigContainer == null) _ConfigContainer = new ConfigContainer();
		return _ConfigContainer;
	}
	
	public synchronized String get(String key, String file){
		String result = null;
		if(ALL_FILE.equalsIgnoreCase(file)){
			for(String f : propertyCache.keySet()){
				//以防死循环
				if(ALL_FILE.equalsIgnoreCase(f)) break;
				result = get(key, f);
				if(StringUtils.isNotBlank(result)) break;
			}
		}
		//没有该文件，则加载
		if(!loaderCache.containsKey(file)){
			if(logger.isDebugEnabled()){
				logger.error("未找到文件file="+ file);
			}
			throw new ConfigLocalLoadException(String.format("没有找到文件[%s]对应加载类!", file));
		}else {
			if(!loaderCache.get(file).isHasLoad()){
				loaderCache.get(file).load();
			}
		}
		if(propertyCache.containsKey(file))
			return propertyCache.get(file).get(key);
		return result;
	}
	/**
	 * 注册到容器中
	 * @param file
	 * @param property
	 */
	public synchronized void register(Class<? extends ConfigLocalLoader> _clazz){
		try {
			ConfigLocalLoader loader = _clazz.newInstance();
			loaderCache.put(loader.getFileName(), loader);
		} catch (Exception e) {
			logger.error(e);
			throw new ConfigLocalLoadException(e);
		}
	}
	/**
	 * 注册到容器中
	 * @param file
	 * @param property
	 */
	public synchronized void register(String className){
		try {
			Object obj = ClassUtils.newInstance(className, new Object[]{});
			if(obj instanceof ConfigLocalLoader){
				ConfigLocalLoader loader = (ConfigLocalLoader)obj;
				loaderCache.put(loader.getFileName(), loader);
			}
		} catch (Exception e) {
			logger.error(e);
			throw new ConfigLocalLoadException(e);
		}
	}
	/**
	 * 注册到容器中
	 * @param file
	 * @param property
	 */
	public synchronized void registerCache(String file, Map<String, String> property){
		evict(file);
		
		propertyCache.put(file, property);
	}
	/**
	 * 注册到容器中
	 * @param file
	 * @param property
	 */
	public synchronized void registerCache(String file, Properties property){
		evict(file);
		
		Map<String, String> prop = new HashMap<String, String>();
		
		for(Object key : property.keySet()){
			prop.put(key.toString(), property.get(key).toString());
		}
		propertyCache.put(file, prop);
	}
	/**
	 * 从容器中移除
	 * @param file
	 */
	public synchronized void evict(Object file){
		if(propertyCache.containsKey(file)){
			propertyCache.remove(file);
			loaderCache.remove(file);
		}
	}

	public synchronized void destroy(){
		propertyCache.clear();
		loaderCache.clear();
		propertyCache = null;
		loaderCache = null;
		_ConfigContainer = null;
	}


	public Object get(Object arg0) {
		return get(arg0.toString(),  ALL_FILE);
	}
	/**
	 * 获得指定类下的所有属性 KEY-VALUE
	 * @param _clazz
	 * @return
	 */
	public Map<String,String> getProp(Class<? extends ConfigLocalLoader> _clazz){
		Object obj = ClassUtils.newInstance(_clazz, new Object[]{});
		
		if(obj instanceof ConfigLocalLoader){
			ConfigLocalLoader l = (ConfigLocalLoader)obj;
			if(propertyCache.get(l.getFileName()) != null) return propertyCache.get(l.getFileName());
			if(loaderCache.containsKey(l.getFileName()) &&
					!loaderCache.get(l.getFileName()).isHasLoad()){
				loaderCache.get(l.getFileName()).load();
			}
			return propertyCache.get(l.getFileName());
		}
		return null;
	}

	public void put(Object arg0, Object arg1) {
		if(arg1 instanceof Properties){
			this.registerCache(arg0.toString(), (Properties)arg1);
		}else if(arg1 instanceof Map){
			this.registerCache(arg0.toString(), (Map<String, String>)arg1);
		}
	}
}
